#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>

template <class T>
class BlockQueue
{
    static const int defalutNum = 20;
public:
    BlockQueue(int maxCapacity = defalutNum) :_maxCapacity(maxCapacity)
    {
        // 初始化互斥量mutex和条件变量cond
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
        // _lowWater = _maxCapacity / 4;
        // _highWater = _maxCapacity*3 / 4; 
    }

    T pop()
    {
        pthread_mutex_lock(&_mutex); 
        // 因为判断临界资源调试是否满足, 也是在访问临界资源！判断资源是否就绪, 是通过再临界资源内部判断的

        while (_q.size() == 0)  // while而不是if是为了做到防止线程被伪唤醒的情况
        {
            pthread_cond_wait(&_c_cond, &_mutex);
        }

        T out = _q.front();
        _q.pop();

        pthread_cond_signal(&_p_cond);
        // if (_q.size() <= _lowWater) pthread_cond_signal(&_p_cond);
        pthread_mutex_unlock(&_mutex);
        return out;
    }

    void push(const T &in)
    {
        pthread_mutex_lock(&_mutex);
        // 因为判断临界资源调试是否满足, 也是在访问临界资源！判断资源是否就绪, 是通过再临界资源内部判断的。

        while (_q.size() == _maxCapacity) // while而不是if是为了做到防止线程被伪唤醒的情况
        {
            pthread_cond_wait(&_p_cond, &_mutex);
        }

        // 1. 队列没满  2. 被唤醒
        _q.push(in);

        pthread_cond_signal(&_c_cond);
        // if (_q.size() >= _highWater) pthread_cond_signal(&_c_cond);
        pthread_mutex_unlock(&_mutex);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }

private:
    std::queue<T> _q;  // 共享资源, q被当作整体使用, 因为只有一份, 所以需要加锁.
    int _maxCapacity;  // 极值
    pthread_mutex_t _mutex;
    pthread_cond_t _c_cond;
    pthread_cond_t _p_cond;
    // int _lowWater;
    // int _highWater;
};